//type主要是给类型起“别名” 类型涉及到组合 联合类型（类型的复用） 字面量类型 ->

import { getConstantValue } from "../node_modules/typescript/lib/typescript";

//interface 不能使用联合类型 可以继承和实现（有的时候可以使用type 有的时候可以使用interface）

//类类型 将一个类来描述类型  -> 可以描述实例
class Animal1 { }
let instance: Animal1 = new Animal1;

//安装ts之后会存在一些内置类型 IArguments dom元素 事件......

//类型断言（!非空断言去掉空的情况 null/undefined） as 语法强转（string<xxx>)
//js语法 ？链判断运算符 如果为空则返回 不过有值就可以继续取值
//??来排除null和undefined, 只要不是null和undefined都走后边的条件 false||true  = true

//函数 进行类型的标识(表达式声明 函数声明 function)
//函数的类型 主要关心参数和返回值（可选参数 默认值 剩余参数）this声明 函数的重载（参数不同 返回值不同）
//函数不能只使用 arguments 还需要限制 函数的参数

//函数的返回值也可以限制类型

//类正常使用和es6一致 没有大的区别（修饰符 public protected private readonly）ts中类的属性 必须要先声明才能使用

//readonly 只能在constructor中初始化参数 其他地方不能修改
//ts支持装饰器 实验性语法后期可能会发生变化 可以修饰类 类的属性 类的方法（语法糖） 
//@connect 高阶函数 @withRouter
function a(this: any) {
    this
}
//接口 用来描述（数据格式 形状的）对象类型的 可以描述对象 还可以用来描述函数；接口只可以描述复杂类型

//在接口里写void 表示不关心返回什么
interface IFn {//混合接口
    (): void,  //描述自己是一个函数
    readonly a?: () => void //描述属性 所以写void 不进行检测返回值
}
const fn: IFn = () => {
    return 'abc'
}
fn.a
//接口里也可以使用一些修饰符 readonly 表示接口的属性仅读的

//如果接口中数据比预定的多如何解决（1.断言已经存在的接口 2：利用兼容性 多的属性可以赋予给少的 3：接口可以扩展 扩展新的接口来使用 4：同名的接口可以自己合并）
//ts是具备兼容性的 当我们做复制的操作的时候 ts

//接口可以被其他人来实现 可以是类来实现接口
interface Speakable {//也可以规定类中的属性
    speak: () => void
}
interface speakEnglish {
    speckEnglish: () => void
}
//类中要满足接口的实现
class Speak implements Speakable, speakEnglish {
    speak() { }
    speckEnglish() { }
}

let speack = new Speak();


//抽象类可以包含具体的实现
abstract class Animal {//子类继承后续 需要自己实现名字
    abstract name: string;//强调自己不是先 子类来实现 抽象类不能被new
    abstract speak(): void;//子类需要实现
    //抽象类中可以定义成非抽象的方法
    eat() {
        console.log("抽象eat");
    }
}
class Cat extends Animal {
    public name: string = "TOM"
    speak() { }
}
// namespace Speak{
//     export const a=1;
// }


//interfave任意接口 string可以兼容所有的key
interface IArgs {
    [x: string]: any //key只能是string或者number
}
let args: IArgs = {
    a: 1,
    1: 'x',
    [Symbol()]: '1'
}


//泛型无法做运算 如果两个字符串相加 那么返回的就是字符串 两个数字相加就是数字
//可以限制泛型的返回  泛型的约束
function sum<T extends (number)>(a: T, b: T): T {
    return (a + b) as T;//只是告诉返回值是T 但是你没法限制 a+b能相加
}
sum(1, 2);
//sum(1, 2); 
//如果写好一个具体的类型 表示限制死了 传入的类型 看一下当前传入的内容是否带有某个属性

function finish<T extends { kind: string }>(val: T) {//我们希望限制传入的内容 带有能游泳的表示
}
finish({ kind: '草鱼' }); //redux type属性

//根据泛型 产生多个类型默认泛型
//interface //产生一个对象 name属性可以随时更改类型
type MType<T = string> = { name: T }
type MName1 = MType
type MName2 = MType<number>

//用默认值来规定泛型的不确定性 因为不传递参数 值是unknown

//我们期望在一个对象中 能获取对象的属性
//K 满足 T
function getVal<T extends object, K extends keyof T>(val: T, key: K) {

}
type r = keyof string;//联合类型 并集
type r2 = keyof any;//string|number|symbol 约定的 都能作为key
getVal({ a: 1, b: 2 }, 'a')

//交叉类型 交叉表示2个人公用的部分
interface A {
    handsome: string,
    type: number
}

interface B {
    high: string,
    type: string
}

type AB = A & B;//交集
let person: AB = {
    handsome: '帅',
    high: '高',
    type: 'abc' as never
}

//两个对象 我想做一个合并
function mixin(o1, o2) {

}
mixin({}, {})
export { }